package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import com.tanhua.admin.service.MqMessageService;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.utils.Constants;
import com.tanhua.commons.utils.UserHolder;
import com.tanhua.domain.UserInfo;
import com.tanhua.dubbo.api.CommentApi;
import com.tanhua.dubbo.api.MovementApi;
import com.tanhua.dubbo.api.UserInfoApi;
import com.tanhua.dubbo.api.VisitorsApi;
import com.tanhua.mongo.Comment;
import com.tanhua.mongo.Movement;
import com.tanhua.mongo.Visitors;
import com.tanhua.myenum.CommentType;
import com.tanhua.server.exception.BusinessException;
import com.tanhua.vo.ErrorResult;
import com.tanhua.vo.MovementsVo;
import com.tanhua.vo.PageResult;
import com.tanhua.vo.VisitorsVo;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MovementService {
    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private CommentApi commentApi;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @DubboReference
    private VisitorsApi visitorsApi;

    @Autowired
    private MqMessageService mqMessageService;

    /**
     * 发布动态方法
     *
     * @param movement
     * @param multipartFiles
     */
    public void publish(Movement movement, MultipartFile[] multipartFiles) throws IOException {
        //发布动态为空，不允许发布
        if (movement.getTextContent() == null) {
            throw new BusinessException(ErrorResult.contentError());
        }
        //设置当前用户ID
        Long userId = UserHolder.getUserId();
        movement.setUserId(userId);
        //将当前内容上传至阿里云oss，获取请求地址
        ArrayList<String> list = new ArrayList();
        for (MultipartFile multipartFile : multipartFiles) {
            String s = ossTemplate.saveMassage(multipartFile.getOriginalFilename(), multipartFile.getInputStream());
            list.add(s);
        }
        //将数据封装到movement对象
        movement.setMedias(list);
        //调用api完成发布动态
        String movementId = movementApi.publish(movement);
        //将动态id发送到交换机
        mqMessageService.sendAudiService(movementId);
    }

    /**
     * 查看我的动态
     *
     * @param userId
     * @param page
     * @param pagesize
     */
    public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
        //根据用户id，调用API查询个人动态内容（PageResult  -- Movement）
        PageResult pageResult = movementApi.findByUserId(userId, page, pagesize);
        //获取PageResult中的item列表对象
        List<Movement> items = (List<Movement>) pageResult.getItems();
        //非空判断
        if (items == null) {
            return pageResult;
        }
        //获取用户信息
        UserInfo userInfo = userInfoApi.findById(userId);
        //循环数据列表
        ArrayList<MovementsVo> list = new ArrayList<>();
        for (Movement item : items) {
            //一个Movement构建一个Vo对象
            MovementsVo vo = MovementsVo.init(userInfo, item);
            list.add(vo);
        }
        //构建返回值
        pageResult.setItems(list);
        return pageResult;
    }


    /**
     * 查询好友动态
     *
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult findFriendMovement(Integer page, Integer pagesize) {
        //获取当前用户ID
        Long userId = UserHolder.getUserId();
        //去动态时间线表根据好友id查询movement列表
        PageResult pageResult = movementApi.findFriendMovement(userId, page, pagesize);
        //判断列表是否为空
        List<Movement> items = (List<Movement>) pageResult.getItems();
        if (items == null || items.size() == 0) {
            return pageResult;
        }
        //获取movement中ids，查询到Map<id,UserInfo>
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, null);
        //将movement和UserInfo封装为vo返回
        ArrayList<MovementsVo> list = new ArrayList();
        for (Movement item : items) {
            UserInfo userInfo = map.get(item.getUserId());
            if (userInfo != null) {
                MovementsVo vo = MovementsVo.init(userInfo, item);
                //修复点赞状态,喜欢状态的bug，判断key是否存在
                String key = Constants.MOVEMENTS_INTERACT_KEY + item.getId();
                String loveKey = Constants.MOVEMENT_LOVE_HASHKEY + userId;
                String likeKey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
                if(redisTemplate.opsForHash().hasKey(key,loveKey)){
                    vo.setHasLoved(1);
                }
                if(redisTemplate.opsForHash().hasKey(key,likeKey)){
                    vo.setHasLiked(1);
                }
                list.add(vo);
            }
        }
        //为pageResult设置items
        pageResult.setItems(list);
        return pageResult;
    }

    /**
     * 推荐动态
     *
     * @param page
     * @param pagesize
     * @return
     */
    public PageResult recommend(Integer page, Integer pagesize) {
        //获取当前用户id
        Long userId = UserHolder.getUserId();
        //从redis中获取推荐的PID
        String redisData = (String) redisTemplate.opsForValue().get(Constants.MOVEMENTS_RECOMMEND + userId);
        //构建空的movement集合
        //List<Movement> movementList = new ArrayList<>();
        List<Movement> movementList = Collections.emptyList();
        //判断pid是否为空
        if (StringUtils.isEmpty(redisData)) {
            //如果redisData为空，则使用随机推荐数据
            movementList = movementApi.randomMovement(pagesize);
        } else {
            //判断是否需要分页
            String[] split = redisData.split(",");
            //判断当前页的起始条数是否小于数组总数
            if ((page - 1) * pagesize < split.length) {
                List<Long> pids = Arrays.stream(split).skip((page - 1) * pagesize)
                        .limit(pagesize)
                        .map(item -> Long.valueOf(item))
                        .collect(Collectors.toList());
                //redisData非空，调用api查询推荐动态内容
                movementList = movementApi.pidMovement(pids, page, pagesize);
            }
        }

        //!!!与好友动态代码相似，可抽取公共代码块
        PageResult pageResult = new PageResult(page, pagesize, 0L, null);
        //判断列表是否为空
        if (movementList == null) {
            return pageResult;
        }
        //获取movement中ids，查询到Map<id,UserInfo>
        List<Long> ids = CollUtil.getFieldValues(movementList, "userId", Long.class);
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, null);
        //将movement和UserInfo封装为vo返回
        ArrayList<MovementsVo> voList = new ArrayList();
        for (Movement movement : movementList) {
            UserInfo userInfo = map.get(movement.getUserId());
            if (userInfo != null) {
                MovementsVo vo = MovementsVo.init(userInfo, movement);
                //修复点赞状态的bug，判断key是否存在
                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId();
                String loveKey = Constants.MOVEMENT_LOVE_HASHKEY + userId;
                String likeKey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
                if(redisTemplate.opsForHash().hasKey(key,loveKey)){
                    vo.setHasLoved(1);
                }
                if(redisTemplate.opsForHash().hasKey(key,likeKey)){
                    vo.setHasLiked(1);
                }
                voList.add(vo);
            }
        }
        //为pageResult设置items
        pageResult.setItems(voList);
        return pageResult;

    }


    /**
     * 查询单条动态
     *
     * @param id
     * @return
     */
    public MovementsVo findById(String id) {
        //根据id查询动态
        Movement movement = movementApi.findById(id);

        //将动态封装为vo返回
        UserInfo userInfo = null;
        if (movement != null) {
            userInfo = userInfoApi.findById(movement.getUserId());
        }
        return MovementsVo.init(userInfo, movement);
    }

    /**
     * 点赞，喜欢或取消点赞，取消喜欢方法
     *
     * @param movementId
     * @param commentType
     * @param flag
     * @return
     */
    public Integer likeOrLove(String movementId, CommentType commentType, boolean flag) {
        //1,调用api判断用户是否已进行该操作
        Long userId = UserHolder.getUserId();
        boolean isDone = commentApi.getStatus(movementId, userId, commentType);
        //2,操作错误，抛出不同类型错误,1是点赞，3是喜欢
        //2.1 如果用户来喜欢，但表中数据已喜欢，抛出用户已喜欢错误
        if (isDone && commentType.getType() == 3 && flag) {
            throw new BusinessException(ErrorResult.loveError());
            //2.2 如果用户来取消喜欢，但表中无喜欢数据，抛出用户已未喜欢错误
        } else if (!isDone && commentType.getType() == 3 && !flag) {
            throw new BusinessException(ErrorResult.disloveError());
            //2.3 如果用户来点赞，但表中数据已点赞，抛出用户已点赞错误
        } else if (isDone && commentType.getType() == 1 && flag) {
            throw new BusinessException(ErrorResult.likeError());
            //2.4 如果用户来取消点赞，但表中无点赞数据，抛出用户未点赞错误
        } else if (!isDone && commentType.getType() == 1 && !flag) {
            throw new BusinessException(ErrorResult.disLikeError());
        }
        //3,拼接redis的key，将用户的点赞状态存入redis
        String hashKey;
        if (commentType.getType() == 1) {
            hashKey = Constants.MOVEMENT_LIKE_HASHKEY + userId;
        } else {
            hashKey = Constants.MOVEMENT_LOVE_HASHKEY + userId;
        }
        //4,封装处理数据
        Integer count;
        String key = Constants.MOVEMENTS_INTERACT_KEY + movementId;
        if (flag) {
            //3.1 将数据存入mongodb
            Comment comment = new Comment();
            comment.setPublishId(new ObjectId(movementId));
            comment.setCommentType(commentType.getType());
            comment.setUserId(userId);
            count = commentApi.save(comment);
            redisTemplate.opsForHash().put(key,hashKey,"1");
        } else {
            //3.2 将数据从mongodb移除
            count = commentApi.delete(movementId, userId, commentType);
            redisTemplate.opsForHash().delete(key,hashKey,"1");
        }
        return count;
    }

    /**
     * 谁看过我接口
     * @return
     */
    public List<VisitorsVo> visitors() {
        //查询访问时间
        String key = Constants.VISITORS_USER;
        String hashKey = String.valueOf(UserHolder.getUserId());
        String value = (String) redisTemplate.opsForHash().get(key,hashKey);
        Long date = StringUtils.isEmpty(value) ? null : Long.valueOf(value);
        //调用api查询visitors
        List<Visitors> visitorsList = visitorsApi.getVisitors( UserHolder.getUserId(),date);
        redisTemplate.opsForHash().put(key,hashKey,System.currentTimeMillis());
        //判断集合是否为空,为空返回一个空集合
        if(visitorsList == null || visitorsList.size() == 0){
            return new ArrayList();
        }
        //收集集合中的访客id
        List<Long> ids = CollUtil.getFieldValues(visitorsList, "visitorUserId", Long.class);
        //获取用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, null);
        //封装vo对象返回
        ArrayList<VisitorsVo> vos = new ArrayList<>();
        for (Visitors visitors : visitorsList) {
            UserInfo userInfo = map.get(visitors.getVisitorUserId());
            if(userInfo != null){
                VisitorsVo vo = VisitorsVo.init(userInfo, visitors);
                vos.add(vo);
            }
        }
        return vos;
    }

}
